package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.sc.nft.dao.MallLogisticsDao;
import com.sc.nft.dao.MallOrderDao;
import com.sc.nft.entity.MallLogistics;
import com.sc.nft.entity.MallOrder;
import com.sc.nft.entity.vo.LogisticsVO;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.LogisticsQuery;
import com.sc.nft.service.MallLogisticsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 物流信息表(MallLogistics)表服务实现类
 *
 * @author wwc
 * @since 2023-05-17 13:17:43
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallLogisticsServiceImpl implements MallLogisticsService {

    private final MallLogisticsDao mallLogisticsDao;
    private final MallOrderDao mallOrderDao;

    private final LogisticsQuery logisticsQuery;

    private final RedisTemplate redisTemplate;

    @Override
    public LogisticsVO get(String logisticsId,String tel) {
        String info = logisticsQuery.get(logisticsId, tel);
        if (StrUtil.isEmpty(info)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(info, JSONObject.class);
        String data = jsonObject.getString("data");
        if (StrUtil.isEmpty(data)) {
            return null;
        }
        LogisticsVO logisticsVO = new LogisticsVO();
        logisticsVO.setName(jsonObject.getString("kdmc"));
        logisticsVO.setLogisticsId(jsonObject.getString("kddh"));
        logisticsVO.setStatus(jsonObject.getInteger("status"));
        logisticsVO.setLogisticsData(data);
        return logisticsVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<LogisticsVO> getByOrderIdAndLogisticsId(String orderId, String logisticsIds) {
        String[] logisticsIdList = logisticsIds.split(",");
        List<LogisticsVO> logisticsVOList = new ArrayList<>();
        for (String logisticsId : logisticsIdList) {
            // 验证缓存,当前的物流信息倒计时是否存在.如果不存在的话,直接调用物流接口,并且在缓存中打标记
            String key = StrUtil.format("logistics:{}-{}", orderId, logisticsId);
            Boolean hasKey = redisTemplate.hasKey(key);
            MallLogistics byOrderIdAndLogisticsId = mallLogisticsDao.getByOrderIdAndLogisticsId(orderId, logisticsId);
            MallOrder byId = mallOrderDao.getByOrderNo(orderId);
            if (BeanUtil.isEmpty(byId)) {
                throw new GlobalRunTimeException("订单不存在");
            }
            // 数据存在且已经在数据库,判定物流是否签收
            if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
                // 4:为签收,10:为拒收并且已经发回签收
                if (byOrderIdAndLogisticsId.getStatus().equals(4) || byOrderIdAndLogisticsId.getStatus().equals(10)) {
                    LogisticsVO logisticsVO = new LogisticsVO();
                    BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
                    logisticsVO.setOrderId(0);
                    logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
                    logisticsVOList.add(logisticsVO);
                    continue;
                }
            }

            if (hasKey) {
                // 标记存在,直接从数据库里面拿数据,标记如果存在的情况下,就一定会有数据存在
                LogisticsVO logisticsVO = new LogisticsVO();
                BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
                logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
                logisticsVOList.add(logisticsVO);
                continue;
            }
            // 标记不存在,调用物流接口,并且在缓存中打标记,同时数据入库
            LogisticsVO logisticsVO = this.get(logisticsId, byId.getUserTel());
            if (BeanUtil.isEmpty(logisticsVO)) {
                continue;
            }
            // 判定数据是否存在,存在需要更新
            if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
                BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
                logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
                byOrderIdAndLogisticsId.updateById();
            } else {
                // 不存在的数据需要写入订单id后新增
                byOrderIdAndLogisticsId = new MallLogistics();
                BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
                byOrderIdAndLogisticsId.setOrderId(orderId);
                logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
                byOrderIdAndLogisticsId.insert();
            }
            // 打标记
            redisTemplate.opsForValue().set(key, "1", 2, TimeUnit.HOURS);
            logisticsVOList.add(logisticsVO);
        }
        return logisticsVOList;
    }

    @Override
    public LogisticsVO getByIdAndLogisticsId(Long id, String logisticsIds) {
        String[] logisticsIdList = logisticsIds.split(",");
        String logisticsId = logisticsIdList[0];
        // 验证缓存,当前的物流信息倒计时是否存在.如果不存在的话,直接调用物流接口,并且在缓存中打标记
        String key = StrUtil.format("logistics:{}-{}", id, logisticsId);
        Boolean hasKey = redisTemplate.hasKey(key);
        MallOrder byId = mallOrderDao.getById(id);
        if (BeanUtil.isEmpty(byId)) {
            throw new GlobalRunTimeException("订单不存在");
        }
        MallLogistics byOrderIdAndLogisticsId = mallLogisticsDao.getByOrderIdAndLogisticsId(byId.getOrderNo(), logisticsId);

        // 数据存在且已经在数据库,判定物流是否签收
        if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
            // 4:为签收,10:为拒收并且已经发回签收
            if (byOrderIdAndLogisticsId.getStatus().equals(4) || byOrderIdAndLogisticsId.getStatus().equals(10)) {
                LogisticsVO logisticsVO = new LogisticsVO();
                BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
                logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
                return logisticsVO;
            }
        }

        if (hasKey) {
            // 标记存在,直接从数据库里面拿数据,标记如果存在的情况下,就一定会有数据存在
            LogisticsVO logisticsVO = new LogisticsVO();
            BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
            logisticsVO.setOrderId(0);
            logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
            return logisticsVO;
        }
        // 标记不存在,调用物流接口,并且在缓存中打标记,同时数据入库
        LogisticsVO logisticsVO = this.get(logisticsId, byId.getUserTel());
        if (BeanUtil.isEmpty(logisticsVO)) {
            return logisticsVO;
        }
        // 判定数据是否存在,存在需要更新
        if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
            BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
            logisticsVO.setOrderId(0);
            logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
            byOrderIdAndLogisticsId.updateById();
        } else {
            // 不存在的数据需要写入订单id后新增
            byOrderIdAndLogisticsId = new MallLogistics();
            BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
            byOrderIdAndLogisticsId.setOrderId(byId.getOrderNo());
//            logisticsVO.setOrderId(0);
            logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
            byOrderIdAndLogisticsId.insert();
        }
        // 打标记
        redisTemplate.opsForValue().set(key, "1", 2, TimeUnit.HOURS);
        return logisticsVO;
    }


    @Override
    public List<LogisticsVO> batchGetByIdAndLogisticsId(Long id, String logisticsIds) {
        String[] logisticsIdList = logisticsIds.split(",");
        List<LogisticsVO> logisticsVOList = new ArrayList<>();
        for (String logisticsId : logisticsIdList) {
            // 验证缓存,当前的物流信息倒计时是否存在.如果不存在的话,直接调用物流接口,并且在缓存中打标记
            String key = StrUtil.format("logistics:{}-{}", id, logisticsId);
            Boolean hasKey = redisTemplate.hasKey(key);
            MallOrder byId = mallOrderDao.getById(id);
            if (BeanUtil.isEmpty(byId)) {
                throw new GlobalRunTimeException("订单不存在");
            }
            MallLogistics byOrderIdAndLogisticsId = mallLogisticsDao.getByOrderIdAndLogisticsId(byId.getOrderNo(), logisticsId);

            // 数据存在且已经在数据库,判定物流是否签收
            if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
                // 4:为签收,10:为拒收并且已经发回签收
                if (byOrderIdAndLogisticsId.getStatus().equals(4) || byOrderIdAndLogisticsId.getStatus().equals(10)) {
                    LogisticsVO logisticsVO = new LogisticsVO();
                    BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
                    logisticsVO.setOrderId(0);
                    logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
                    logisticsVOList.add(logisticsVO);
                    continue;
                }
            }

            if (hasKey) {
                // 标记存在,直接从数据库里面拿数据,标记如果存在的情况下,就一定会有数据存在
                LogisticsVO logisticsVO = new LogisticsVO();
                BeanUtil.copyProperties(byOrderIdAndLogisticsId, logisticsVO);
                logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(byOrderIdAndLogisticsId.getLogisticsData(), LogisticsVO.LogisticsData.class));
                logisticsVOList.add(logisticsVO);
                continue;
            }
            // 标记不存在,调用物流接口,并且在缓存中打标记,同时数据入库
            LogisticsVO logisticsVO = this.get(logisticsId, byId.getUserTel());
            if (BeanUtil.isEmpty(logisticsVO)) {
                continue;
            }
            // 判定数据是否存在,存在需要更新
            if (BeanUtil.isNotEmpty(byOrderIdAndLogisticsId)) {
                BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
                logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
                byOrderIdAndLogisticsId.updateById();
            } else {
                // 不存在的数据需要写入订单id后新增
                byOrderIdAndLogisticsId = new MallLogistics();
                BeanUtil.copyProperties(logisticsVO, byOrderIdAndLogisticsId);
                byOrderIdAndLogisticsId.setOrderId(byId.getOrderNo());
//            logisticsVO.setOrderId(0);
                logisticsVO.setData(JSONObject.parseArray(logisticsVO.getLogisticsData(), LogisticsVO.LogisticsData.class));
                byOrderIdAndLogisticsId.insert();
            }
            // 打标记
            redisTemplate.opsForValue().set(key, "1", 2, TimeUnit.HOURS);
            logisticsVOList.add(logisticsVO);
        }
        return logisticsVOList;
    }

}
